/*
 * @Description:
 * @Version: 1.0
 * @Autor: lzc
 * @Date: 2021-12-28 09:11:10
 * @LastEditors: lzc
 * @LastEditTime: 2021-12-29 12:47:42
 */
#include "sntp.h" /* LwIP SNTP example */

/* Variable holding number of times ESP32 restarted since first boot.
 * It is placed into RTC memory using RTC_DATA_ATTR and
 * maintains its value when ESP32 wakes from deep sleep.
 */
static const char *TAG = "SNTP";

static void obtain_time(void);
static void initialize_sntp(void);

static void Counter(void *pvParameters);

static void SNTP_Data_Parse(const char *str);

SNTP_time_data_t SNTP_Time;

#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
void sntp_sync_time(struct timeval *tv)
{
    settimeofday(tv, NULL);
    ESP_LOGI(TAG, "Time is synchronized from custom code");
    sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
}
#endif

void time_sync_notification_cb(struct timeval *tv)
{
    ESP_LOGI(TAG, "Notification of a time synchronization event");
}

SemaphoreHandle_t SNTP_GetSyncTime = NULL;

void sntp_Task(void *pvParameters)
{
    time_t now;
    struct tm timeinfo;
    SNTP_GetSyncTime = xSemaphoreCreateBinary();
    xSemaphoreGive(SNTP_GetSyncTime);
    xTaskCreate(Counter, "SNTP_Time_Over", 1024, NULL, 3, NULL);
    while (1)
    {
        if (xSemaphoreTake(SNTP_GetSyncTime, 10))
        {
            time(&now);
            localtime_r(&now, &timeinfo);
            // Is time set? If not, tm_year will be (1970 - 1900).
            if (timeinfo.tm_year < (2016 - 1900))
            {
                ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
                obtain_time();
                // update 'now' variable with current time
                time(&now);
            }
            char strftime_buf[64];
            // Set timezone to China Standard Time
            setenv("TZ", "CST-8", 1);
            tzset();

            localtime_r(&now, &timeinfo);
            strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
            ESP_LOGD(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
            SNTP_Data_Parse(strftime_buf);
        }
        vTaskDelay(100);
    }
}

static void Counter(void *pvParameters)
{
    TickType_t xLastTime = xTaskGetTickCount();
    while (1)
    {
        if (xTaskGetTickCount() - xLastTime >= (100 * 12))
        {
            xLastTime = xTaskGetTickCount();
            if (SNTP_GetSyncTime != NULL)
            {
                xSemaphoreGive(SNTP_GetSyncTime);
            }
        }
        vTaskDelay(100);
    }
}

static void obtain_time(void)
{
    initialize_sntp();

    // wait for time to be set
    time_t now = 0;
    struct tm timeinfo = {0};
    int retry = 0;
    const int retry_count = 10;
    while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count)
    {
        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
    time(&now);
    localtime_r(&now, &timeinfo);
}

static void initialize_sntp(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "ntp1.aliyun.com");
    sntp_setservername(1, "210.72.145.44"); // 国家授时中心服务器 IP 地址
    sntp_setservername(2, "1.cn.pool.ntp.org");
    sntp_setservername(3, "pool.ntp.org");

    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
    sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
#endif
    sntp_init();
}

static void SNTP_Data_Parse(const char *str)
{
    // Tue Dec 28 16:47:24 2021
    char Time[10];
    char *buf[3], *p;
    int i = 0;
    p = NULL;
    sscanf(str, "%s %s %s %s %s", SNTP_Time.week, SNTP_Time.Month, SNTP_Time.Date, Time, SNTP_Time.Year);
    // printf("%s %s %s %s %s \n", SNTP_Time.week, SNTP_Time.Month, SNTP_Time.Date, Time, SNTP_Time.Year);
    /*
    分割同一字符串，第一次调用时传入字符串的首地址，第二个参数是分割符
    这里的分割符是空格，假如 buf = "hello;world;123"，你还可以按照 ";" 来分割buf
    此时第二个参数就填写 ";"
    */
    p = strtok(Time, ":");
    while (p)
    {
        buf[i] = p;
        ++i;
        // 再次调用分割时指针要变为NULL, 也就是这里的第一个参数，分割的字符串还是str
        // 第二个参数要和第一次调用时的分割符保持一致
        p = strtok(NULL, ":");
    }
    memcpy(SNTP_Time.Hour, buf[0], sizeof(buf));
    memcpy(SNTP_Time.Minute, buf[1], sizeof(buf));
    memcpy(SNTP_Time.Second, buf[2], sizeof(buf));
    // printf("%s\n%s\n%s\n", SNTP_Time.Hour, SNTP_Time.Minute, SNTP_Time.Second);
}
